/**
 * @(#)CoordinadorBundlesSimple.java Jan 29, 2007
 *
 * Copyright (c) 2005-2010 Psiqueware S.A. de C.V. All Rights Reserved.
 * This software is the proprietary information Psiqueware S.A. de C.V.
 * Use is subject to license terms.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * <br/>Usuario : AngelElectrico
 * <br/>Creaci&oacute;n: Jan 29, 2007 - 12:57:49 PM
 * <br/>
 * <br/>
 * <br/><t5>Cambios :</t5>
 * <br/><b>Fecha | Autor  |  Cambios</b>
 * <ul>
 * <li>Feb 16, 2007 | <a href = "mailto:AngelElectrico@PsiqueWare.com">Angel El&eacute;ctrico</a> | Creaci&oacute;n del Objeto.</li>
 *
 * </ul>
 */

package com.psiqueware.alheli.i18n.osgi;

import com.psiqueware.alheli.exception.NullArgumentException;
import com.psiqueware.alheli.i18n.CoordinadorBundles;
import com.psiqueware.alheli.i18n.propertyBundles.BasicoResourceBundleCombinado;

import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

/**
 * Coordinador de Bundles que tiene
 * m&eacute;todos especiales para ser utilizados por diferentes threads y
 * diferentes classloaders.
 * <br/>Paquete Original: com.psiqueware.basico.i18n.propertyBundles
 * <br/>Nombre  Original: CoordinadorBundlesSimple
 * <br/>Oprima para ver : <a href="CoordinadorBundlesSimple.java.html"><i>C&oacute;digo Fuente</i> </a>
 *
 * @author <a href="mailto:AngelElectrico@PsiqueWare.com">Angel El&eacute;ctrico</a>
 * @version Revision: 1.1 Feb 16, 2007 12:57:49 PM
 */
public class CoordinadorBundlesOsgi implements CoordinadorBundles
{

    /**
     * Nombres de los Bundles.
     */
    private final Map<String, ContextoBundleOsgi> m_contextos = new HashMap<String, ContextoBundleOsgi>();

    /**
     * Constructor de CoordinadorBundlesSimple.
     */
    public CoordinadorBundlesOsgi()
    {

    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param contexto    en esta implementaci&oacute;n no se utiliza.
     * @param baseName    nombre base del bundle.
     * @param classLoader a cargar.
     */
    public void agregarResourceBundle(final String contexto, final String baseName, ClassLoader classLoader)
    {
        if (null == baseName)
            throw new NullArgumentException("<error>El argumento 'baseName' no puede ser NULL.</error>");
        if (null == classLoader) classLoader = Thread.currentThread().getContextClassLoader();

        synchronized (m_contextos)
        {
            ContextoBundleOsgi contextoBundleOsgi = m_contextos.get(contexto);
            if (null == contextoBundleOsgi)
            {
                contextoBundleOsgi = new ContextoBundleOsgi(contexto);
                m_contextos.put(contexto, contextoBundleOsgi);
            }
            if (!contextoBundleOsgi.containsClassLoader(classLoader)) contextoBundleOsgi.addClassLoader(classLoader);
            if (!contextoBundleOsgi.containsClassLoader(CoordinadorBundlesOsgi.class.getClassLoader()))
                contextoBundleOsgi.addClassLoader(CoordinadorBundlesOsgi.class.getClassLoader());
            if (!contextoBundleOsgi.containsBaseNames(baseName)) contextoBundleOsgi.addBaseName(baseName);
        }
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param contexto en esta implementaci&oacute;n no se utiliza.
     * @param baseName nombre base del bundle.
     */
    public void agregarResourceBundle(String contexto, String baseName)
    {
        agregarResourceBundle(contexto, baseName, baseName.getClass().getClassLoader());
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param contexto en el que se definir&aacute; el Bundle.
     * @param baseName nombre base del bundle.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(String contexto, String baseName, Locale locale)
    {
        agregarResourceBundle(contexto, baseName, locale.getClass().getClassLoader());
        return getBundle(locale, contexto);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param contexto      en el que se definir&aacute; el Bundle.
     * @param classBaseName nombre base del bundle.
     */
    public void agregarResourceBundle(String contexto, Class classBaseName)
    {
        agregarResourceBundle(contexto, classBaseName.getName(), classBaseName.getClassLoader());
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param baseName nombre base del bundle.
     */
    public void agregarResourceBundle(final String baseName)
    {
        agregarResourceBundle("", baseName, baseName.getClass().getClassLoader());

    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param classBaseName nombre base del bundle.
     */
    public void agregarResourceBundle(final Class classBaseName)
    {
        agregarResourceBundle("", classBaseName.getName(), classBaseName.getClassLoader());
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param contexto      en el que se definir&aacute; el Bundle.
     * @param classBaseName nombre base del bundle.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(String contexto, Class classBaseName, Locale locale)
    {
        agregarResourceBundle(contexto, classBaseName.getName(), classBaseName.getClassLoader());
        return getBundle(locale, contexto);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param classBaseName nombre base del bundle.
     * @param locale        {@link Locale} del bundle buscado.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(final Class classBaseName, final Locale locale)
    {
        return agregaBuscaResourceBundle("", classBaseName, locale);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param baseName nombre base del bundle.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(final String baseName)
    {
        return agregaBuscaResourceBundle("", baseName, Locale.getDefault());
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param classBaseName nombre base del bundle.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(final Class classBaseName)
    {
        return agregaBuscaResourceBundle("", classBaseName, Locale.getDefault());
    }

    /**
     * Devuelve un ResourceBundle para un {@link Locale} sin tomar en cuenta el contexto.
     *
     * @param locale   localidad cuyos recursos se buscan.
     * @param contexto para el Bundle. No se utiliza pero cumple con el contrato de la interfaze.
     *
     * @return {@link ResourceBundle}.
     */
    public ResourceBundle getBundle(Locale locale, String contexto)
    {
        final BasicoResourceBundleCombinado combinado = new BasicoResourceBundleCombinado(locale);
        synchronized (m_contextos)
        {
            final ContextoBundleOsgi contextoBundleOsgi = m_contextos.get(contexto);
            if (null == contextoBundleOsgi)
                throw new MissingResourceException("No se encontr&oacute; un contexto bundle para: " + contexto, ContextoBundleOsgi.class.getName(), contexto);

            final List<String> baseNames = contextoBundleOsgi.getBaseNames();
            final List<ClassLoader> loaders = contextoBundleOsgi.getClassLoaders();
            for (final String baseName : baseNames)
            {
                ResourceBundle bundle = null;
                for (final ClassLoader loader : loaders)
                {
                    try
                    {
                        bundle = ResourceBundle.getBundle(baseName, locale, loader);
                        if (null != bundle) break;
                    }
                    catch (final MissingResourceException e)
                    {
                        //
                    }
                }
                if (null == bundle)
                {
                    throw new MissingResourceException("No se encontr&oacute; un Bundle para el nombre base: " + baseName + "\nContexto: " + contextoBundleOsgi, ResourceBundle.class.getName(), baseName);
                }
                combinado.agregarRecursos(bundle);
            }
        }
        return combinado;
    }

    /**
     * Devuelve un ResourceBundle para el {@link Locale} sin importarle el contexto de los recursos.
     *
     * @param locale localidad cuyos recursos se buscan.
     *
     * @return {@link ResourceBundle}.
     */
    public ResourceBundle getBundle(Locale locale)
    {
        return getBundle(locale, "");
    }

    /**
     * Devuelve un ResourceBundle sin importarle el contexto de los recursos y utilizando el {@link Locale} por defecto.
     *
     * @return {@link ResourceBundle}.
     */
    public ResourceBundle getBundle()
    {
        return getBundle(Locale.getDefault(), "");
    }

}